package com.utils.basehelper.encrypt;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.Map;
import java.util.Set;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;

import sun.misc.BASE64Decoder;

public class EncrypUtil {
	

	/**
	 * 用MD5 生成唯一token
	 * 
	 * @param paramStr
	 * @return
	 */
	public static String createToken(String paramStr) {
		paramStr = paramStr + new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) /*+ InitConst.TOKEN_KEY*/;
		try {
			return createToken(paramStr, "MD5");
		} catch (Exception e) {
			return paramStr;
		}
	}

	/**
	 * 使用指定加密类型 生成token
	 * @param inStr
	 * @param type
	 * @return
	 * @throws Exception
	 */
	private static String createToken(String inStr, String type) throws Exception {
		MessageDigest md = null;
		String out = null;
		try {
			md = MessageDigest.getInstance(type);
			byte[] digest = md.digest(inStr.getBytes());
			out = byte2hex(digest);
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
			throw e;
		}
		return out;
	}

	/**
	 * 二进制转化为16进制
	 * @param b
	 * @return
	 */
	private static String byte2hex(byte[] b) {
		String hs = "";
		String stmp = "";
		for (int n = 0; n < b.length; n++) {
			stmp = Integer.toHexString(b[n] & 0xFF);
			if (stmp.length() == 1)
				hs = hs + "0" + stmp;
			else {
				hs = hs + stmp;
			}
		}
		return hs.toUpperCase();
	}

	/**
	 * 根据请求的关键参数，按照字典排序，拼接上uri,再用md5生成sign。MD5(/tt/api/user/getuser?uuid=1&times=1111&token=lodad)
	 * @param params:uuid times token等.
	 * 		  uri:/tt/api/user/getuser. 
	 * @return
	 */
	public static String createSign(String uri,Map<String, String> params, boolean encode) throws Exception {
		Set<String> keysSet = params.keySet();
		Object[] keys = keysSet.toArray();
		Arrays.sort(keys);
		StringBuffer temp = new StringBuffer();
		boolean first = true;
		temp.append(uri);
		temp.append("?");
		for (Object key : keys) {
			if (first) {
				first = false;
			} else {
				temp.append("&");
			}
			temp.append(key).append("=");
			Object value = params.get(key);
			String valueString = "";
			if (null != value) {
				valueString = String.valueOf(value);
			}
			if (encode) {
				temp.append(URLEncoder.encode(valueString, "UTF-8"));
			} else {
				temp.append(valueString);
			}
		}
//		System.out.println(temp.toString());
		return EncrypUtil.createToken(temp.toString(), "MD5").toUpperCase();
	}

	/**
	 * SHA1加密
	 * @param input
	 * @return
	 * @throws NoSuchAlgorithmException
	 */
	public static String sha1(String input) throws NoSuchAlgorithmException {
		MessageDigest mDigest = MessageDigest.getInstance("SHA1");
		byte[] result = mDigest.digest(input.getBytes());
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < result.length; i++) {
			sb.append(Integer.toString((result[i] & 0xff) + 0x100, 16).substring(1));
		}
		return sb.toString();
	}

	//TODO 使用AES-128-CBC加密模式，key需要为16位,key和iv可以相同！
	private static String KEY = ""/*InitConst.TOKEN_KEY + InitConst.SIGN_KEY*/;
//	private static String IV = InitConst.TOKEN_KEY + InitConst.SIGN_KEY;
	private static String SF = "AES/CBC/NoPadding";
	
	/**
	 * 使用默认的key和iv加密
	 * @param data
	 * @return
	 * @throws Exception
	 */
	public static String encrypt(String data) throws Exception {
//		System.out.println(KEY);
		if(data==null||"".equals(data)) {
			return "";
		}
		return encrypt(data, KEY);
	}

	/**
	 * 使用默认的key和iv解密
	 * @param data
	 * @return
	 * @throws Exception
	 */
	public static String desEncrypt(String data) throws Exception {
		if(data==null||"".equals(data)) {
			return "";
		}
		return desEncrypt(data, KEY);
	}

	/**
	 * 根据token加密
	 * @param data
	 * @param token
	 * @return
	 * @throws Exception
	 */
	public static String encryptByToken(String data, String token) throws Exception {
		if(data==null||"".equals(data)) {
			return "";
		}
		return encrypt(data, token.substring(0, 16));
	}
	
	/**
	 * 根据token解密
	 * @param data
	 * @param token
	 * @return 
	 * @throws Exception
	 */
	public static String desEncryptByToken(String data, String token) throws Exception {
		if(data==null||"".equals(data)) {
			return "";
		}
		return desEncrypt(data, token.substring(0, 16));
	}
	
	/**
	 * 加密方法
	 * @param data 要加密的数据
	 * @param key 加密key
	 * @param iv 加密iv
	 * @return 加密的结果
	 * @throws Exception
	 */
	public static String encrypt(String data, String key) throws Exception {
		try {

			Cipher cipher = Cipher.getInstance(SF);// "算法/模式/补码方式"
			int blockSize = cipher.getBlockSize();

			byte[] dataBytes = data.getBytes();
			int plaintextLength = dataBytes.length;
			if (plaintextLength % blockSize != 0) {
				plaintextLength = plaintextLength + (blockSize - (plaintextLength % blockSize));
			}

			byte[] plaintext = new byte[plaintextLength];
			System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length);

			SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");
			IvParameterSpec ivspec = new IvParameterSpec(key.getBytes());//iv

			cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
			byte[] encrypted = cipher.doFinal(plaintext);

			return new Base64().encodeToString(encrypted).trim();

		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * 解密方法
	 * @param data 要解密的数据
	 * @param key 解密key
	 * @param iv 解密iv
	 * @return 解密的结果
	 * @throws Exception
	 */
	public static String desEncrypt(String data, String key) throws Exception {
		try {
			byte[] encrypted1 = new Base64().decode(data);

			Cipher cipher = Cipher.getInstance(SF);
			SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");
			IvParameterSpec ivspec = new IvParameterSpec(key.getBytes());//iv

			cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);

			byte[] original = cipher.doFinal(encrypted1);
			String originalString = new String(original);
			return originalString.trim();
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	//TODO 生成唯一邀请码
	public static String createInviteCode(String id) {
		int a = 8-id.length();
		String code = "";
		if(a>0) {
			for (int i = 0; i < a; i++) {
				code += "0";
			}
			code += id;
		}
		return a>0?code:id;
	}

	/**
	 * base64转化为inputStream
	 * @param data
	 * @return
	 * @throws IOException
	 */
	public static InputStream base64ToInputStream(String data) throws IOException{
		data = data.replace("data:image/jpeg;base64,", "");
		byte[] encrypted = new BASE64Decoder().decodeBuffer(data);
		InputStream is = new ByteArrayInputStream(encrypted);
		return is;
	}
	
	
	/**
	 * 测试
	 */
	public static void main(String args[]) throws Exception {
//
//		long nowTimes = DateUtil.getMills(new Date(), null)/1000;
//		System.out.println(nowTimes);
//		
//		long times = DateUtil.getMills(new Date(), null)/1000;
//    	String phone = "";
    	
		System.out.println(createToken("1553850381", "MD5")); ;

		
		
	}
}